//==============================================================================
//
//               Copyright (C) 2007  Dick van Oudheusden
//  
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2007-11-04 15:29:14 $ $Revision: 1.18 $
//
//==============================================================================

#include "ofc/config.h"

#include "ofc/DGraphicScreen.h"
#include "ofc/DScreenHandler.h"
#include "ofc/DTrueTypeFont.h"
#include "ofc/DPNGImage.h"
#include "ofc/DJPEGImage.h"
#include "ofc/DFile.h"
#include "ofc/DTimer.h"

#include "DInc.h"
#include "DTest.h"


#ifdef HAVE_DGRAPHICSCREEN


//
// Screen Handler class
// 
@interface DTestGraphicScreen : Object <DScreenHandler>
{
@private
  int             _counter; // the check counter
  DGraphicScreen *_screen;  // the screen
  DColor         *_fgc;
  DColor         *_bgc;

  unsigned         _keyX;
  unsigned         _keyY;
  unsigned         _locationX;
  unsigned         _locationY;
  unsigned         _buttonX;
  unsigned         _buttonY;
  unsigned         _stateX;
  unsigned         _stateY;

#ifdef HAVE_DTRUETYPEFONT
  DTrueTypeFont   *_font;
#endif
  DGraphicSurface *_inputSurface;
}

- (DTestGraphicScreen *) init;
- open;
- draw;
- waitEvents;
- close;
- (BOOL) keyPress :(DKey *) key :(int) state;
- (BOOL) mouseMove :(unsigned) x :(unsigned) y;
- (BOOL) mouseButtonPress :(DKey *) button :(int) state;
- (BOOL) screenResize :(unsigned) maxX :(unsigned) maxY;
- (BOOL) screenFocus :(BOOL) focus;
- (BOOL) screenRedraw :(unsigned) minX :(unsigned) maxX :(unsigned) minY :(unsigned) maxY;
#ifdef HAVE_DPNGIMAGE
- (unsigned) drawPNGImage :(const char *) name :(DFile *) file :(DPNGImage *) image :(unsigned) x;
#endif
#ifdef HAVE_DJPEGIMAGE
- (unsigned) drawJPEGImage :(const char *) name :(DFile *) file :(DJPEGImage *) image :(unsigned) x;
#endif

@end


@implementation DTestGraphicScreen

- (DTestGraphicScreen *) init
{
  [super init];
  
  _counter      = 0;
  _screen       = [DGraphicScreen new];
  _fgc          = [DColor new];
  _bgc          = [DColor new];

#ifdef HAVE_DTRUETYPEFONT
  _font         = [DTrueTypeFont new];
#endif
  _inputSurface = [DGraphicSurface new];
  
  return self;
}


- open
{
  [_fgc set :0   :255 :255];
  [_bgc set :255 :255 :224];
  
#ifdef HAVE_DTRUETYPEFONT
  if (![_font open :"arial.ttf"])
  {
    printf("font not open !!!\n");
  }
#endif
  
  TEST([_screen open :600 :300 :0 :_fgc :_bgc]);

  [_screen screenHandler :self];
  
  return self;
}


- draw
{
  if ([_screen isOpen])
  {
    int           y;
    unsigned char alpha;
    

    TEST([_screen startDrawing]);

    [_fgc set :0   :255 :255];
    [_bgc set :255 :255 :224];
    TEST([_screen color :_fgc :_bgc]);
    [_screen clear];
    

    [_screen clip :60 :12 :96 :[_screen maxY]-20];
    [_fgc textColor :DCLR_BLACK];
    [_bgc textColor :DCLR_BLUE];
    TEST([_screen color :_fgc :_bgc]);
    [_screen clear];
  
    [_screen clip :108 :12 : 144 :[_screen maxY]-20];
    [_fgc textColor :DCLR_BLACK];
    [_bgc textColor :DCLR_RED];
    TEST([_screen color :_fgc :_bgc]);
    [_screen clear];
  
    [_screen cursor :10 :0];
    TEST([_screen tell] == 10);
  
    [_screen cursor :10 :5];
    TEST([_screen tell] == (10 + 5 * [_screen width]));
  
    [_screen skip :[_screen width] - 1];
    TEST([_screen tell] == (9 + 6 * [_screen width]));
  
    TEST([_screen cursorX] == 9);
    TEST([_screen cursorY] == 6);
  
    [_screen seek :(5 + 15 * [_screen width]) :0];
  
    TEST([_screen cursorX] == 5);
    TEST([_screen cursorY] == 15);
  
    [_screen seek :(2 + 2 * [_screen width]) :1];
  
    TEST([_screen cursorX] == 7);
    TEST([_screen cursorY] == 17);
  
    [_screen seek :0 :2];
  
    TEST([_screen cursorX] == [_screen maxX]);
    TEST([_screen cursorY] == [_screen maxY]);

    [_screen clip];
    
    [_fgc set :0   :0   :0];
    [_bgc set :255 :255 :224];
  
    TEST([_screen color :_fgc :_bgc]);
    
    [_screen drawHLine :12 :12 :48 :DDW_LINE_SOLID];
    [_screen drawVLine :[_screen maxY] - 20];
  
    [_screen drawLine :12 :12 :48 :[_screen maxY] - 20];

    TEST([_screen lineType] == DDW_LINE_SOLID);
    
    TEST([_screen cursorX] == 48);
    TEST([_screen cursorY] == [_screen maxY] - 20);

    [_screen drawHLine :12];
    [_screen drawLine  :48 :12];
    [_screen drawVLine :12 :[_screen maxY] - 20 : 12];

    [_screen cursor :156 :[_screen maxY] - 60]; // ToDo: beter
    [_screen writeText :"Keys: "]; 
    _keyX = [_screen cursorX]; _keyY = [_screen cursorY];
    
    [_screen cursor :156 :[_screen maxY] - 50];
    [_screen writeText :"Mouse location: "];
    _locationX = [_screen cursorX]; _locationY = [_screen cursorY];
     
    [_screen cursor :156 :[_screen maxY] - 40];
    [_screen writeText :"Mouse button: "];
    _buttonX = [_screen cursorX]; _buttonY = [_screen cursorY];

    [_screen cursor :156 :[_screen maxY] - 30];
    [_screen writeText :"Mouse state: "];
    _stateX = [_screen cursorX]; _stateY = [_screen cursorY];

    // Dashed and dotted
    [_screen drawHLine :12 :[_screen maxY] - 15 :144 :DDW_LINE_DASHED];
    
    TEST([_screen lineType] == DDW_LINE_DASHED);

    [_screen drawVLine :160 :12 :[_screen maxY] - 100];

    TEST([_screen dashLength] == 10);
    
    [_screen dashLength :20];
    
    TEST([_screen dashLength] == 20);

    [_screen drawVLine :180 :12 :[_screen maxY] - 100];
    
    [_screen dashLength :10];
    
    [_screen drawLine  :60 :12 :96 :[_screen maxY] - 20 :DDW_LINE_DASHED];
    
    [_screen drawVLine :170 :12 :[_screen maxY] - 100 : DDW_LINE_DOTTED];

    TEST([_screen lineType] == DDW_LINE_DOTTED);
    
    [_screen drawHLine :12 :[_screen maxY] - 10 :144];

    [_screen drawLine  :96 :12 :60 :[_screen maxY] - 20];
    
    // [screen cursor :DDW_CURSOR_OFF];

    [_screen lineType :DDW_LINE_SOLID];
    
    [_screen drawBezierLine :400 :12 :410 :[_screen maxY]/2 :[_screen maxX]-24 :[_screen maxY]/2 :[_screen maxX]-12 :[_screen maxY]-12];

    // Alpha blending
    y = 2;
    for (alpha = 255; alpha > 0; alpha--)
    {
      [_fgc alpha :alpha];
      
      [_screen foregroundColor :_fgc];
      
      [_screen drawHLine :2 :y :[_screen maxX]-2];
       
       y++;
    }
      
    [_screen blit :240 :12 :_screen :10 :120 :120 :180];

    [_fgc alpha :255];
    [_screen foregroundColor :_fgc];

#ifdef HAVE_DTRUETYPEFONT
    if ([_font isOpen])
    {
      TEST([_font size :16 :16]);
      
      [_screen font :_font];
    }
#endif
    
#ifdef HAVE_DPNGIMAGE
    {
      DPNGImage *pngImage = [DPNGImage new];
      DFile     *pngFile  = [DFile     new];
      int        y        = 12;
      
      if ([pngFile open :"tennis.jpg" :"rb"])
      {
        TEST(![DPNGImage isImage :pngFile]);
        
        [pngFile close];
      }
      
      y = [self drawPNGImage :"bgan6a16.png" :pngFile :pngImage :y];
      y = [self drawPNGImage :"basn3p04.png" :pngFile :pngImage :y];
      y = [self drawPNGImage :"basn0g02.png" :pngFile :pngImage :y];
      y = [self drawPNGImage :"basn6a16.png" :pngFile :pngImage :y];
      y = [self drawPNGImage :"tbbn1g04.png" :pngFile :pngImage :y];

      if ([pngFile open :"ofc.png" :"w"])
      {
        if ([pngImage open :pngFile :500 :200 :3])
        {
          TEST([_screen readImage :50 :50 :pngImage]);
        
          [pngImage close];
        }
        else
          TEST(NO);
        
        [pngFile close];
      }
      else
        TEST(NO);
        
      [pngImage free];
      [pngFile  free];
    }
#endif
 
#ifdef HAVE_DJPEGIMAGE
    {
      DJPEGImage *jpegImage = [DJPEGImage new];
      DFile      *jpegFile  = [DFile     new];
      int        x          = 240;
      
      if ([jpegFile open :"tennis.jpg" :"rb"])
      {
        TEST([DJPEGImage isImage :jpegFile]);
        
        [jpegFile close];
      }

      if ([jpegFile open :"test.png" :"rb"])
      {
        TEST(![DJPEGImage isImage :jpegFile]);
        
        [jpegFile close];
      }

      x = [self drawJPEGImage :"testimg.jpg" :jpegFile :jpegImage :x];

      if ([jpegFile open :"ofc.jpg" :"w"])
      {
        if ([jpegImage open :jpegFile :500 :200 :75])
        {
          TEST([_screen readImage :50 :50 :jpegImage]);
        
          [jpegImage close];
        }
        else
          TEST(NO);
        
        [jpegFile close];
      }
      else
        TEST(NO);

      [jpegImage free];
      [jpegFile  free];
    }
#endif

    [_screen writeText :156 :[_screen maxY]-20 :"Press q to quit.."];

    [_screen font :nil];
    
    [_screen stopDrawing];

    
    if ([_inputSurface open :200 :60 :_fgc :_bgc])
    {
      [_inputSurface startDrawing];
      
      [_inputSurface blit :0 :0 :_screen :156 :[_screen maxY] - 60 :356 :[_screen maxY]];
      
      [_inputSurface stopDrawing];
    }
  }
  
  return self;
}


- waitEvents
{
  [_screen waitEvents];
  
  return self;
}

#ifdef HAVE_DPNGIMAGE
- (unsigned) drawPNGImage :(const char *) name :(DFile *) file :(DPNGImage *) image :(unsigned) y
{
  if ([file open :name :"rb"])
  {
    if ([[image class] isImage :file])
    {
      if ([image open :file])
      {
        TEST([_screen writeImage :200 :y :image]);
        
        y += [image height] + 2;
            
        [image close];
      }
      else
        TEST(NO);
    }
    else
      TEST(NO);
    
    [file close];
  }
  else
    TEST(NO);
  
  return y;
}
#endif

#ifdef HAVE_DJPEGIMAGE
- (unsigned) drawJPEGImage :(const char *) name :(DFile *) file :(DJPEGImage *) image :(unsigned) x
{
  if ([file open :name :"rb"])
  {
    if ([[image class] isImage :file])
    {
      if ([image open :file])
      {
        TEST([_screen writeImage :x :80 :image]);

        x += [image width] + 10;
            
        [image close];
      }
      else
        TEST(NO);
    }
    else
      TEST(NO);
    
    [file close];
  }
  else
    TEST(NO);
  return x;
}
#endif

- close
{
  [_fgc    free];
  [_bgc    free];
  
  [_screen free];

#ifdef HAVE_DTRUETYPEFONT
  [_font   free];
#endif
  
  [_inputSurface free];
  
  return self;
}


- (BOOL) keyPress :(DKey *) key :(int) state
{
  DText *info = [key toText];

  [_screen startDrawing];
  
  if ([_inputSurface isOpen])
  {
    [_screen blit :156 :[_screen maxY] - 60 :_inputSurface :0 :0 :[_inputSurface maxX] :[_inputSurface maxY]];
  }
  
  [_screen cursor    :_keyX :_keyY];
  
  [_screen writeText :[[info ljust :10] cstring]];
  [_screen stopDrawing];
  
  [info free];
  
  return ([key key] != 'q');
}


- (BOOL) mouseMove :(unsigned) x :(unsigned) y
{
  DText *info = [DText new];
  
  [info format :"x%d y%d", x, y];

  [_screen startDrawing];
  
  if ([_inputSurface isOpen])
  {
    [_screen blit :156 :[_screen maxY] - 60 :_inputSurface :0 :0 :[_inputSurface maxX] :[_inputSurface maxY]];
  }

  [_screen cursor :_locationX :_locationY];
  [_screen writeText :[[info ljust :10] cstring]];
  [_screen stopDrawing];
  
  [info free];
  
  return YES;
}


- (BOOL) mouseButtonPress :(DKey *) button :(int) state
{
  DText *info = [button toText];
  
  [self draw];
  
  [_screen startDrawing];

  if ([_inputSurface isOpen])
  {
    [_screen blit :156 :[_screen maxY] - 60 :_inputSurface :0 :0 :[_inputSurface maxX] :[_inputSurface maxY]];
  }
  
  [_screen cursor :_buttonX :_buttonY];
  [_screen writeText :[[info ljust :10] cstring]];
  
  [info format :"%d", state];
  [_screen cursor :_stateX :_stateY];
  [_screen writeText :[[info ljust :10] cstring]];
  [_screen stopDrawing];
  
  [info free];
  
  return YES;
}

- (BOOL) screenResize :(unsigned) maxX :(unsigned) maxY
{
  DText *info = [DText new];
  
  [_screen startDrawing];
  
  [info format :"Resize: %d - %d", maxX, maxY];
  
  [_screen writeText :5 :2 :[info cstring]];
  
  [_screen stopDrawing];
  
  [info free];

  return YES;
}

- (BOOL) screenFocus :(BOOL) focus
{
  [_screen startDrawing];
  [_screen cursor    :5 :1];
  if (focus)
    [_screen writeText :"focus!"];
  else
    [_screen writeText :"lost!"];
  [_screen stopDrawing];
        
  return YES;
}

- (BOOL) screenRedraw :(unsigned) minX :(unsigned) maxX :(unsigned) minY :(unsigned) maxY
{
  return YES;
}

@end
#endif  

void DGraphicScreen_test()
{
#ifdef HAVE_DGRAPHICSCREEN
  
  DTestGraphicScreen *screen = [DTestGraphicScreen new];
  
  STARTTEST();

  [screen open];
  
  [screen draw];
  
  [screen waitEvents];
  
  [screen close];
  
  STOPTEST();
#endif
}
